﻿/* 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

 * 
 * CodeDefender 
 * Copyright © 2010 http://codedefender.codeplex.com (oguz@bastemur.com)
 */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace CodeDefender
{
    public partial class Form1 : Form
    {
        public Form1()
        {  
            AsmProc = null; 
            Helpers.ILVersions = new List<string>();
            Helpers.locationOfBinaries();
            InitializeComponent();

            cbPlatform.SelectedIndex = 0;

            if (Helpers.ILVersions.Count > 0)
            {
                foreach (string ver in Helpers.ILVersions)
                    cbVersion.Items.Add(ver);
                cbVersion.SelectedIndex = 0;  
            }
            else
            {
                cbVersion.Enabled = false;
            } 
        } 

        private void cbVersion_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cbVersion.SelectedIndex < 0)
                return;
            txtFolder.Text = cbVersion.Items[cbVersion.SelectedIndex].ToString();
            btnProtect.Enabled = false;
            txtFile.Text = "";
            txtOut.Text = "";
        }

        private void btnFolder_Click(object sender, EventArgs e)
        {
            folderBrowserDialog1.SelectedPath = "";
            folderBrowserDialog1.ShowDialog();
            if (folderBrowserDialog1.SelectedPath != "")
            {
                if (File.Exists(folderBrowserDialog1.SelectedPath + @"\VC\vcvarsall.bat"))
                {
                    if (!Helpers.ILVersions.Contains(folderBrowserDialog1.SelectedPath + @"\VC\"))
                    {
                        Helpers.ILVersions.Add(folderBrowserDialog1.SelectedPath + @"\VC\");
                        cbVersion.Items.Add(folderBrowserDialog1.SelectedPath + @"\VC\");
                        if (cbVersion.SelectedIndex < 0)
                        {
                            cbVersion.SelectedIndex = 0;
                            cbVersion.Enabled = true;
                        }
                    }
                    else
                    {
                        MessageBox.Show("Current list contains the folder you selected!");
                    }
                }
                else
                {
                    MessageBox.Show("There are no required files in the folder you selected!");
                }
            }
        }

        System.Diagnostics.Process AsmProc; 
        void Protect(string app, string message, bool goProtect)
        {
            if (AsmProc != null)
            {
                AsmProc.Kill();
            } 

            System.Diagnostics.ProcessStartInfo asmInfo = new System.Diagnostics.ProcessStartInfo("cmd.exe");
            
            asmInfo.RedirectStandardError = true;
            asmInfo.RedirectStandardOutput = true;
            asmInfo.RedirectStandardInput = true;
            asmInfo.UseShellExecute = false; 

            AsmProc = new System.Diagnostics.Process();
            
            AsmProc.StartInfo = asmInfo;
            AsmProc.EnableRaisingEvents = true;
            AsmProc.Exited += new EventHandler(AsmProc_Exited);
            AsmProc.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(AsmProc_OutputDataReceived);
            AsmProc.SynchronizingObject = this.txtOut;

            txtOut.Text = "Started..";
            hasError = false;
            btnProtect.Enabled = false;

            bool status = false;

            try
            {
                status = AsmProc.Start();
                AsmProc.StandardInput.WriteLine("@echo off");
                AsmProc.StandardInput.WriteLine("\"" + txtFolder.Text + "\\vcvarsall.bat\" x86"+ ((cbPlatform.SelectedIndex==1)?"_amd64":"") );
                AsmProc.StandardInput.WriteLine(app);
                AsmProc.StandardInput.WriteLine("exit");
                txtOut.Text += AsmProc.StandardOutput.ReadToEnd();
                txtOut.Text += "\r\nDone!\r\n\r\n" + message; 
            }
            catch (System.Exception e)
            {
                txtOut.Text += "\r\nError:\r\n\t" + e.Message;
                hasError = true;
            } 
        }

        bool hasError;

        void AsmProc_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
        {
            txtOut.Text += e.Data;
            hasError = true;
        }

        void AsmProc_Exited(object sender, EventArgs e)
        {  
            if (!hasError)
            {
                if (txtOut.Text.Contains("Protect The Code"))
                {
                    btnProtect.Enabled = true;
                    GenerateTypes();
                }
                else
                {
                    btnProtect.Enabled = false;
                }
            }

            AsmProc.Dispose();
            AsmProc = null;
        } 

        private void btnFile_Click(object sender, EventArgs e)
        {
            openFileDialog1.FileName = "";
            openFileDialog1.ShowDialog();
            if (openFileDialog1.FileName != "")
            {
                txtFile.Text = openFileDialog1.FileName;
                string args ="\""+ txtFile.Text + "\" /quoteallnames /out:\"" + Application.StartupPath + "\\Output.il\" /typelist";
                Protect("ildasm.exe "+ args, "Click 'Protect The Code!' button", true);
            }
        }

        Dictionary<String, String> codes = null;
        Dictionary<String, String> bases = null;
        string[] code_lines = null;

        bool GenerateTypes()
        {
            StreamReader Rd = new StreamReader(Application.StartupPath + "\\Output.il");
            string theCode = Rd.ReadToEnd();
            Rd.Close();

            int start = theCode.IndexOf(".typelist");
            if (start < 0)
            {
                txtOut.Text += "\r\nILDASM couldnt disassembly the target binary!";
                return false;
            }
            int end = theCode.IndexOf("}", start);
            string sub = theCode.Substring(start + 13, end - (start + 13));
            sub = sub.Replace("\r\n", "").Trim().Replace("'.'", "|").Replace("'", "");
            string[] list = sub.Split(' ');

            if (codes == null)
            {
                codes = new Dictionary<String, String>();
                bases = new Dictionary<String, String>();
            }
            else
            {
                codes.Clear();
                bases.Clear();
            }

            int count = 1;
            foreach (string str in list)
            {
                if (str.Length == 0)
                    continue;
                string[] sub_list = str.Split('|');
                for (int i = 0, len = sub_list.Length; i < len; i++)
                {
                    if (sub_list[i] == "Resources" || sub_list[i] == "Settings")
                        continue;

                    if (i != 0)
                    {
                        if (!codes.ContainsKey(sub_list[i]))
                        {
                            codes.Add(sub_list[i], new String(' ', count++));
                        }
                    }
                    else
                    {
                        if (!bases.ContainsKey(sub_list[0]))
                        {
                            bases.Add(sub_list[0], new String('_', count++));
                        }
                    }
                }
            }

            code_lines = theCode.Replace("\r\n", "\r").Split('\r');

            for (int i = 0, len = code_lines.Length; i < len; i++)
            {
                string line = code_lines[i];
                if (line.Length == 0)
                    continue;

                string trimLine = line.Trim();

                if (trimLine.StartsWith(".field"))
                {
                    int pos = trimLine.LastIndexOf(' ');
                    string __key = trimLine.Substring(pos + 1, trimLine.Length - (pos + 1)).Replace("'", "").Trim();
                    if (!codes.ContainsKey(__key))
                    {
                        codes.Add(__key, new String(' ', count++));
                    }
                    continue;
                }

                if (trimLine.StartsWith(".method"))
                {
                    while (!line.Contains("cil managed"))
                    {
                        i++;
                        line += " " + code_lines[i];
                    }

                    if (line.Contains("virtual"))
                        if (!line.Contains("newslot"))
                            continue;

                    string fixed_line = line.Trim();
                    int pos = fixed_line.IndexOf('\'');
                    while (pos != -1)
                    {
                        int next_pos = fixed_line.IndexOf('\'', pos + 1);
                        string __key = fixed_line.Substring(pos + 1, next_pos - (pos + 1));

                        if (fixed_line.Length > next_pos + 2)
                        {
                            if (fixed_line[pos - 1] != '.' &&
                                fixed_line[pos - 1] != '[' &&
                                fixed_line[next_pos + 1] != '.' &&
                                fixed_line[next_pos + 1] != ']')
                            {
                                if (!codes.ContainsKey(__key))
                                {
                                    codes.Add(__key, new String(' ', count++));
                                }
                            }

                            pos = fixed_line.IndexOf('\'', next_pos + 1);
                        }
                        else
                            pos = -1;
                    }
                    continue;
                }
            }

            hiddenList.Items.Clear();

            foreach (string str in codes.Keys)
            {
                hiddenList.Items.Add(str, CheckState.Checked);
            }

            return true;
        }

        bool ProtectOut()
        {
            if (code_lines == null)
            {
                return false;
            }

            if (code_lines.Length == 0)
            {
                return false;
            }

            for (int i = 0, len = hiddenList.Items.Count; i < len; i++)
            {
                if (hiddenList.GetItemCheckState(i) == CheckState.Unchecked)
                {
                    codes.Remove(hiddenList.Items[i].ToString());
                }
            }

            string theCode = ""; 

            foreach (string line in code_lines)
            {
                if (line.Length == 0)
                    continue;

                string trimLine = line.Trim();

                if (trimLine.StartsWith(" //"))
                    continue;

                string _line = line;
                if (trimLine.Contains(":  ldstr"))
                { 
                    theCode += _line + "\r\n";
                    continue;
                }  

                foreach (string key in codes.Keys)
                {
                    _line = _line.Replace("'"+key+"'", "'"+codes[key]+"'");
                    foreach (string _base in bases.Keys)
                    {
                        _line = _line.Replace("'" + _base + "." + key, "'" + _base + "." + codes[key]);
                    }
                }
                theCode += _line+"\r\n";
            }

            StreamWriter Wr = new StreamWriter(Application.StartupPath + "\\Output.il");
            Wr.Write(theCode);
            Wr.Close();

            foreach (string key in codes.Keys)
            {
                foreach (string _base in bases.Keys)
                {
                    string []filez = Directory.GetFiles(Application.StartupPath, _base + "." + key + ".*");
                    foreach (string filename in filez)
                    {
                        File.Copy(filename, filename.Replace(key, codes[key]), true);
                    }

                }
            }

            return true;
        } 

        private void btnProtect_Click(object sender, EventArgs e)
        {
            if (ProtectOut())
            {
                string resFile = "";
                if (File.Exists(Application.StartupPath + "\\Output.res"))
                    resFile = " /RESOURCE=Output.res ";

                Protect("ilasm.exe \"" + Application.StartupPath + "\\Output.il\" " + resFile, "Your Application Has Protected.\r\nCheck Output." + txtFile.Text.Substring(txtFile.Text.Length - 3, 3) + " Under The Code Protector Application Folder", false);
            }
        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            System.Diagnostics.Process.Start("http://codedefender.codeplex.com"); 
        } 
    }
}
